package com.admin.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.admin.model.base.PageResult;
import com.admin.model.dto.DeptDto;
import com.admin.model.dto.UserDto;
import com.admin.model.pojo.Dept;
import com.admin.model.pojo.Menu;
import com.admin.model.pojo.User;
import com.admin.model.vo.DeptTreeVo;
import com.admin.model.vo.MenuTreeVo2;
import com.admin.system.dao.CommonDao;
import com.admin.system.dao.DeptDao;
import com.admin.system.dao.UserDao;
import com.admin.system.security.service.UserDetailsServiceImpl;
import com.admin.system.service.DeptService;
import com.admin.system.service.mapstruct.DeptMapper;
import com.admin.system.service.mapstruct.UserMapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.swing.tree.TreeModel;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (Dept)表服务实现类
 *
 * @author makejava
 * @since 2021-01-31 20:16:25
 */
@CacheConfig(cacheNames = "dept")
@Service("deptService")
public class DeptServiceImpl extends ServiceImpl<DeptDao, Dept> implements DeptService {
    @Resource
    private DeptDao deptDao;
    @Resource
    private UserDao userDao;
    @Resource
    private UserMapper userMapper;
    @Resource
    private DeptMapper deptMapper;
    @Resource
    private CommonDao commonDao;

    //@Cacheable(key = "'depts'+#pageSize", unless = "#pageNum>0")
    @Override
    public PageResult queryAll(DeptDto deptDto, int pageNum, int pageSize, String sort) {
        Dept dept = deptMapper.toEntity(deptDto);
        Page<Object> page = PageHelper.startPage(pageNum, pageSize, StrUtil.toUnderlineCase(sort));
        List<Dept> depts = deptDao.queryAll(dept);
        return PageResult.builder()
                .total(page.getTotal())
                .rows(deptMapper.toDto(depts))
                .build();
    }

    @Override
    public DeptDto findById(Long id) {
        return deptMapper.toDto(deptDao.selectById(id));
    }

    @Override
    public List<UserDto> findUserByDeptId(Long deptId) {
        List<User> users = commonDao.queryUserByDeptId(deptId);
        return userMapper.toDto(users);
    }

    @Override
    public List<Tree<String>> buildTree() {
        List<Dept> list = new LambdaQueryChainWrapper<>(deptDao).select(Dept::getId, Dept::getPid, Dept::getName, Dept::getEnabled).list();
        //构建部门树
        List<TreeNode<String>> nodeList = list.stream().map(dept -> new TreeNode<>(dept.getId().toString(), dept.getPid().toString(), dept.getName(), dept.getSort())).collect(Collectors.toList());
        return TreeUtil.build(nodeList, "0");
    }

    @Override
    public List<Tree<String>> buildDuTree() {
        List<Dept> list = new LambdaQueryChainWrapper<>(deptDao).select(Dept::getId, Dept::getPid, Dept::getName, Dept::getEnabled).list();
        LinkedList<TreeNode<String>> treeNodes = new LinkedList<>();
        for (Dept dept : list) {
            LinkedHashMap<String, Object> extra = new LinkedHashMap<>();
            extra.put("children", Lists.newArrayList());
            TreeNode<String> DeptNode = new TreeNode<>(dept.getId().toString(), dept.getPid().toString(), dept.getName(), dept.getSort()).setExtra(extra);
            treeNodes.add(DeptNode);
            List<User> users = commonDao.queryUserByDeptId(dept.getId());
            for (User user : users) {
                TreeNode<String> userNode = new TreeNode<>(user.getId().toString(), dept.getId().toString(), user.getName(), null);
                treeNodes.add(userNode);
            }
        }
        return TreeUtil.build(treeNodes, "0");
    }

    @Override
    public List<DeptDto> queryByPid(Long pid) {
        return deptMapper.toDto(deptDao.queryByPid(pid));
    }

    //@CacheEvict(key = "'depts'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Dept create(DeptDto deptDto) {
        Dept dept = deptMapper.toEntity(deptDto);
        //上级部门是否存在
        if (dept.getPid() != null && dept.getPid() != 0) {
            Dept parDept = deptDao.selectById(dept.getPid());
            Assert.notNull(parDept, "上级部门不存在");
        }
        //部门名称是否存在
        Optional<Dept> optional = new LambdaQueryChainWrapper<>(deptDao)
                .select(Dept::getId)
                .eq(Dept::getPid, dept.getPid())
                .eq(Dept::getName, dept.getName())
                .last("limit 1")
                .oneOpt();
        Assert.isTrue(optional.isPresent(), "部门名称重复");
        int insert = deptDao.insert(dept);
        Assert.isTrue(insert > 0, "创建失败");
        return deptDao.selectById(dept.getId());
    }

    //@CacheEvict(key = "'depts'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteByIds(Set<Long> ids) {
        for (Long id : ids) {
            int delete = deptDao.deleteById(id);
            if (delete > 0) {
                //删除用户授权部门
                userDao.delAuthDeptByDeptId(id);
            }
        }
        //删除所有用户缓存
        UserDetailsServiceImpl.clearCachUserAll();
    }

    //@CacheEvict(key = "'depts'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Dept updateById(DeptDto deptDto) {
        Dept dept = deptMapper.toEntity(deptDto);

        if (dept.getPid() != null && dept.getPid() != 0) {
            Optional.ofNullable(
                    deptDao.selectById(dept.getPid())
            ).orElseThrow(() -> new IllegalArgumentException("上级部门不存在"));
        }

        int update = deptDao.updateById(dept);
        Optional<Dept> optional = new LambdaQueryChainWrapper<>(deptDao)
                .eq(Dept::getPid, dept.getPid())
                .eq(Dept::getName, dept.getName())
                .last("limit 1")
                .oneOpt();
        Assert.isTrue(!(optional.isPresent()), "部门名称重复");
        Assert.isTrue(update > 0, "更新失败");
        //删除所有用户缓存
        UserDetailsServiceImpl.clearCachUserAll();
        return deptDao.selectById(dept.getId());
    }
}